package ocean.chinacraft.common.world.block.function;

import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.HorizontalBlock;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraft.inventory.InventoryHelper;
import net.minecraft.inventory.container.Container;
import net.minecraft.inventory.container.INamedContainerProvider;
import net.minecraft.item.BlockItemUseContext;
import net.minecraft.state.StateContainer;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.*;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.BlockRayTraceResult;
import net.minecraft.util.math.shapes.IBooleanFunction;
import net.minecraft.util.math.shapes.ISelectionContext;
import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.util.math.shapes.VoxelShapes;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.TranslationTextComponent;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.World;
import net.minecraftforge.fml.network.NetworkHooks;
import ocean.chinacraft.common.world.block.function.container.SericultureFrameBlockContainer;
import ocean.chinacraft.common.world.block.properties.PropertiesMisc;
import ocean.chinacraft.common.ModTileEntity;
import ocean.chinacraft.common.tileentity.function.SericultureFrameBlockTile;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.stream.Stream;

/**
 * 养蚕架
 *
 * @author zhang
 * @since 2021/12/15
 */
public class SericultureFrameBlock extends HorizontalBlock {

    private final static VoxelShape SHAPES_N = Stream.of(
            Block.box(4.924999999999997, 2, 12.975000000000001, 10.924999999999994, 4, 13.975000000000001),
            Block.box(2.9250000000000025, 0, 0.9750000000000001, 12.924999999999994, 1, 1.975),
            Block.box(2.9250000000000025, 0, 13.975000000000001, 12.924999999999994, 1, 14.975000000000001),
            Block.box(1.9250000000000007, 0, -0.025000000000000355, 2.9250000000000025, 1, 15.974999999999996),
            Block.box(12.924999999999994, 0, -0.025000000000000355, 13.924999999999994, 1, 15.974999999999996),
            Block.box(3.925000000000006, 0, 1.9749999999999996, 11.924999999999994, 1, 13.975000000000001),
            Block.box(12.924999999999994, 1, 0.9750000000000001, 13.924999999999994, 13, 1.975),
            Block.box(12.924999999999994, 1, 13.975000000000001, 13.924999999999994, 13, 14.975000000000001),
            Block.box(1.9250000000000007, 1, 13.975000000000001, 2.9250000000000025, 13, 14.975000000000001),
            Block.box(1.9250000000000007, 1, 0.9750000000000001, 2.9250000000000025, 13, 1.975),
            Block.box(1.9250000000000007, 12, 0.9750000000000001, 13.924999999999994, 13, 1.975),
            Block.box(2.9250000000000025, 12, 13.975000000000001, 12.924999999999994, 13, 14.975000000000001),
            Block.box(12.924999999999994, 12, 1.9749999999999996, 13.924999999999994, 13, 13.975000000000001),
            Block.box(1.9250000000000007, 12, 1.9749999999999996, 2.9250000000000025, 13, 13.975000000000001),
            Block.box(2.9250000000000025, 13, 1.975, 12.924999999999994, 14, 2.975),
            Block.box(2.9250000000000025, 12, 7.475000000000001, 12.924999999999994, 13, 8.475000000000001),
            Block.box(3.925000000000006, 1, 1.9749999999999996, 11.924999999999994, 2, 13.975000000000001),
            Block.box(10.924999999999994, 2, 1.9749999999999996, 11.924999999999994, 4, 13.975000000000001),
            Block.box(3.925000000000006, 2, 1.9749999999999996, 4.924999999999997, 4, 13.975000000000001),
            Block.box(4.924999999999997, 2, 1.975, 10.924999999999994, 4, 2.975)
    ).reduce((v1, v2) -> VoxelShapes.join(v1, v2, IBooleanFunction.OR)).get();

    private final static VoxelShape SHAPES_W = Stream.of(
            Block.box(13, 2, 5.0000000000000036, 14, 4, 11),
            Block.box(0.9999999999999974, 0, 3.000000000000005, 1.9999999999999973, 1, 12.999999999999995),
            Block.box(14, 0, 3.000000000000005, 15, 1, 12.999999999999995),
            Block.box(-2.4980018054066022e-15, 0, 12.999999999999995, 15.999999999999991, 1, 13.999999999999996),
            Block.box(-2.4980018054066022e-15, 0, 2.000000000000005, 15.999999999999991, 1, 3.000000000000005),
            Block.box(1.9999999999999973, 0, 4.000000000000004, 14, 1, 11.999999999999991),
            Block.box(0.9999999999999974, 1, 2.000000000000005, 1.9999999999999973, 13, 3.000000000000005),
            Block.box(14, 1, 2.000000000000005, 15, 13, 3.000000000000005),
            Block.box(14, 1, 12.999999999999995, 15, 13, 13.999999999999996),
            Block.box(0.9999999999999974, 1, 12.999999999999995, 1.9999999999999973, 13, 13.999999999999996),
            Block.box(0.9999999999999974, 12, 2.000000000000005, 1.9999999999999973, 13, 13.999999999999996),
            Block.box(14, 12, 3.000000000000005, 15, 13, 12.999999999999995),
            Block.box(1.9999999999999973, 12, 2.000000000000005, 14, 13, 3.000000000000005),
            Block.box(1.9999999999999973, 12, 12.999999999999995, 14, 13, 13.999999999999996),
            Block.box(1.9999999999999973, 13, 3.000000000000005, 2.9999999999999973, 14, 12.999999999999995),
            Block.box(7.5, 12, 3.000000000000005, 8.5, 13, 12.999999999999995),
            Block.box(1.9999999999999973, 1, 4.000000000000004, 14, 2, 11.999999999999991),
            Block.box(1.9999999999999973, 2, 4.000000000000004, 14, 4, 5.0000000000000036),
            Block.box(1.9999999999999973, 2, 11, 14, 4, 11.999999999999991),
            Block.box(1.9999999999999973, 2, 5.0000000000000036, 2.9999999999999973, 4, 11)
    ).reduce((v1, v2) -> VoxelShapes.join(v1, v2, IBooleanFunction.OR)).get();

    private final static VoxelShape SHAPES_S = Stream.of(
            Block.box(5.025000000000002, 2, 2.0249999999999986, 11.024999999999999, 4, 3.0249999999999986),
            Block.box(3.025000000000003, 0, 14.024999999999999, 13.024999999999993, 1, 15.024999999999999),
            Block.box(3.025000000000003, 0, 1.0249999999999981, 13.024999999999993, 1, 2.0249999999999986),
            Block.box(13.024999999999993, 0, 0.025000000000007988, 14.024999999999995, 1, 16.025),
            Block.box(2.025000000000003, 0, 0.025000000000007988, 3.025000000000003, 1, 16.025),
            Block.box(4.025000000000004, 0, 2.0249999999999986, 12.02499999999999, 1, 14.024999999999999),
            Block.box(2.025000000000003, 1, 14.024999999999999, 3.025000000000003, 13, 15.024999999999999),
            Block.box(2.025000000000003, 1, 1.0249999999999981, 3.025000000000003, 13, 2.0249999999999986),
            Block.box(13.024999999999993, 1, 1.0249999999999981, 14.024999999999995, 13, 2.0249999999999986),
            Block.box(13.024999999999993, 1, 14.024999999999999, 14.024999999999995, 13, 15.024999999999999),
            Block.box(2.025000000000003, 12, 14.024999999999999, 14.024999999999995, 13, 15.024999999999999),
            Block.box(3.025000000000003, 12, 1.0249999999999981, 13.024999999999993, 13, 2.0249999999999986),
            Block.box(2.025000000000003, 12, 2.0249999999999986, 3.025000000000003, 13, 14.024999999999999),
            Block.box(13.024999999999993, 12, 2.0249999999999986, 14.024999999999995, 13, 14.024999999999999),
            Block.box(3.025000000000003, 13, 13.024999999999999, 13.024999999999993, 14, 14.024999999999999),
            Block.box(3.025000000000003, 12, 7.524999999999997, 13.024999999999993, 13, 8.524999999999997),
            Block.box(4.025000000000004, 1, 2.0249999999999986, 12.02499999999999, 2, 14.024999999999999),
            Block.box(4.025000000000004, 2, 2.0249999999999986, 5.025000000000002, 4, 14.024999999999999),
            Block.box(11.024999999999999, 2, 2.0249999999999986, 12.02499999999999, 4, 14.024999999999999),
            Block.box(5.025000000000002, 2, 13.024999999999999, 11.024999999999999, 4, 14.024999999999999)
    ).reduce((v1, v2) -> VoxelShapes.join(v1, v2, IBooleanFunction.OR)).get();

    private final static VoxelShape SHAPES_E = Stream.of(
            Block.box(1.9499999999999962, 2, 4.999999999999998, 2.949999999999996, 4, 10.999999999999995),
            Block.box(13.949999999999998, 0, 3.0000000000000053, 14.949999999999998, 1, 12.999999999999993),
            Block.box(0.9499999999999944, 0, 3.0000000000000053, 1.9499999999999962, 1, 12.999999999999993),
            Block.box(-0.049999999999994715, 0, 2.0000000000000036, 15.949999999999994, 1, 3.0000000000000053),
            Block.box(-0.049999999999994715, 0, 12.999999999999993, 15.949999999999994, 1, 13.999999999999993),
            Block.box(1.9499999999999962, 0, 4.000000000000009, 13.949999999999998, 1, 11.999999999999993),
            Block.box(13.949999999999998, 1, 12.999999999999993, 14.949999999999998, 13, 13.999999999999993),
            Block.box(0.9499999999999944, 1, 12.999999999999993, 1.9499999999999962, 13, 13.999999999999993),
            Block.box(0.9499999999999944, 1, 2.0000000000000036, 1.9499999999999962, 13, 3.0000000000000053),
            Block.box(13.949999999999998, 1, 2.0000000000000036, 14.949999999999998, 13, 3.0000000000000053),
            Block.box(13.949999999999998, 12, 2.0000000000000036, 14.949999999999998, 13, 13.999999999999993),
            Block.box(0.9499999999999944, 12, 3.0000000000000053, 1.9499999999999962, 13, 12.999999999999993),
            Block.box(1.9499999999999962, 12, 12.999999999999993, 13.949999999999998, 13, 13.999999999999993),
            Block.box(1.9499999999999962, 12, 2.0000000000000036, 13.949999999999998, 13, 3.0000000000000053),
            Block.box(12.949999999999998, 13, 3.0000000000000053, 13.949999999999998, 14, 12.999999999999993),
            Block.box(7.449999999999996, 12, 3.0000000000000053, 8.449999999999996, 13, 12.999999999999993),
            Block.box(1.9499999999999962, 1, 4.000000000000009, 13.949999999999998, 2, 11.999999999999993),
            Block.box(1.9499999999999962, 2, 10.999999999999995, 13.949999999999998, 4, 11.999999999999993),
            Block.box(1.9499999999999962, 2, 4.000000000000009, 13.949999999999998, 4, 4.999999999999998),
            Block.box(12.949999999999998, 2, 4.999999999999998, 13.949999999999998, 4, 10.999999999999995)
    ).reduce((v1, v2) -> VoxelShapes.join(v1, v2, IBooleanFunction.OR)).get();

    public SericultureFrameBlock() {
        super(PropertiesMisc.defaultFunction().noOcclusion());
    }

    @Override
    public VoxelShape getShape(BlockState state, IBlockReader reader, BlockPos pos, ISelectionContext context) {
        Direction direction = state.getValue(FACING);
        switch (direction) {
            case NORTH:
                return SHAPES_N;
            case SOUTH:
                return SHAPES_S;
            case EAST:
                return SHAPES_E;
            case WEST:
                return SHAPES_W;
            default:
                return SHAPES_N;
        }
    }

    @Nullable
    @Override
    public BlockState getStateForPlacement(BlockItemUseContext context) {
        return this.defaultBlockState().setValue(FACING, context.getHorizontalDirection().getOpposite());
    }

    @Override
    public BlockState rotate(BlockState blockState, Rotation rotation) {
        return blockState.setValue(FACING, rotation.rotate(blockState.getValue(FACING)));
    }

    @Override
    public BlockState mirror(BlockState state, Mirror mirror) {
        return state.rotate(mirror.getRotation(state.getValue(FACING)));
    }

    @Override
    protected void createBlockStateDefinition(@Nonnull StateContainer.Builder<Block, BlockState> builder) {
        builder.add(FACING);
    }

    @Override
    public ActionResultType use(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand,
                                BlockRayTraceResult rayTraceResult) {
        if (!world.isClientSide()) {
            TileEntity tileEntity = world.getBlockEntity(pos);
            if (tileEntity instanceof SericultureFrameBlockTile) {
                INamedContainerProvider containerProvider = createContainerProvider(world, pos);
                NetworkHooks.openGui(((ServerPlayerEntity) player), containerProvider, tileEntity.getBlockPos());
            } else {
                throw new IllegalStateException("Our Container provider is missing!");
            }
        }
        return ActionResultType.SUCCESS;
    }

    private INamedContainerProvider createContainerProvider(World worldIn, BlockPos pos) {
        return new INamedContainerProvider() {
            @Nonnull
            @Override
            public ITextComponent getDisplayName() {
                return new TranslationTextComponent("screen.chinacraft.sericulture_frame_block");
            }

            @Override
            public Container createMenu(int i, @Nonnull PlayerInventory playerInventory,
                                        @Nonnull PlayerEntity playerEntity) {
                return new SericultureFrameBlockContainer(i, worldIn, pos, playerInventory, playerEntity);
            }
        };
    }

    @Override
    public void onRemove(BlockState state, World world, BlockPos pos, BlockState state1, boolean flag) {
        if (!state.is(state1.getBlock())) {
            TileEntity tileentity = world.getBlockEntity(pos);
            if (tileentity instanceof SericultureFrameBlockTile) {
                InventoryHelper.dropContents(world, pos, (SericultureFrameBlockTile) tileentity);
                world.updateNeighbourForOutputSignal(pos, this);
            }
            super.onRemove(state, world, pos, state1, flag);
        }
    }

    @Nullable
    @Override
    public TileEntity createTileEntity(BlockState state, IBlockReader world) {
        return ModTileEntity.SERICULTURE_FRAME_BLOCK_TILE.get().create();
    }

    @Override
    public boolean hasTileEntity(BlockState state) {
        return true;
    }
}
